<template>
  <div class="flow-chart-root">
    <div :id="mapId" class="map-container"></div>
    <div style="display: none">
      <div v-for="item in domData" :key="item.domId" :id="item.domId" class="data-txt-container">
        <div v-for="optionItem in txtOptions" class="txt-item">
          <div class="label">{{ optionItem.label }}</div>
          <div class="value">{{ item[optionItem.value] }}</div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import {LineLayer, Marker, PointLayer, Scene} from "@antv/l7";
import {GaodeMap} from "@antv/l7-maps";
import {nextTick, onMounted, watch} from "vue";

const props = defineProps({
  // 点数据
  pointData: {
    type: Object,
    default: () => {
      return {};
    },
  },
  // 流线数据
  lineData: {
    type: Array,
    default: () => {
      return {};
    },
  },
  // 图片数据
  imageList: {
    type: Array,
    default: () => {
      return [];
    },
  },
  // 是否开启点击事件
  addPointMode: {
    type: Boolean,
    default: false
  },
  // 实时数据
  realTimeData: {
    type: Array,
    default: () => {
      return [];
    },
  },
  // 文本X轴偏移量
  offsetX: {
    type: Number,
    default: 80
  },
  // 文本Y轴偏移量
  offsetY: {
    type: Number,
    default: -20
  },
  txtOptions: {
    type: Array,
    default: () => {
      return [
        {
          label: '实时数据',
          value: 'realTime'
        },
        {
          label: '累计数据',
          value: 'cumulative'
        }
      ]
    }
  }
});

let scene = null

const mapLogoVisible = false
const mapId = 'map'

let pointLayer = null;

let pointLayerSource = null

function initPointLayerSource() {
  pointLayerSource = pointLayer.getSource();
}

function createScene() {
  scene = new Scene({
    logoVisible: mapLogoVisible,
    id: mapId,
    map: new GaodeMap({
      pitch: 0,
      style: 'blank ',
      center: [121.435159, 31.256971],
      zoom: 14.89,
      minZoom: 10,
      token: '9aee6df17557d9025c07bdcb52ae2a90'
    })
  });
}

function setMapStatus() {
  const mapHandleStatus = false
  const IStatusOptions = {
    showIndoorMap: mapHandleStatus,
    resizeEnable: mapHandleStatus,
    dragEnable: mapHandleStatus,
    keyboardEnable: mapHandleStatus,
    doubleClickZoom: mapHandleStatus,
    zoomEnable: mapHandleStatus,
    rotateEnable: mapHandleStatus,
  }
  scene.setMapStatus(IStatusOptions)
}

function addLineLayerData() {
  const shapeType = 'line'
  const lineSize = 3
  const baseLineLayer = new LineLayer({zIndex: 10})
      .source(props.lineData, {
        parser: {
          type: 'json',
          coordinates: 'coord'
        }
      })
      .size(lineSize)
      .shape(shapeType)
      .texture('direction')
      .color('rgb(22,119,255)')
      .animate({
        interval: 1, // 间隔
        duration: 1, // 持续时间，延时
        trailLength: 2 // 流线长度
      })
      .style({
        opacity: 0.6,
        lineTexture: true, // 开启线的贴图功能
        iconStep: 10, // 设置贴图纹理的间距
        borderWidth: 0.4, // 默认文 0，最大有效值为 0.5
        borderColor: '#fff' // 默认为 #ccc
      });

  scene.addLayer(baseLineLayer)
}

function addMapImageSource() {
  props.imageList.forEach(({imageId, imageUrl}) => {
    scene.addImage(imageId, imageUrl);
  })
}

function addPointLayer() {
  const mapOpacity = 1
  pointLayer = new PointLayer({zIndex: 10})
      .source(props.pointData)
      .size('size', value => value).style({
        opacity: mapOpacity,
      });
  scene.addLayer(pointLayer);
  changePointLayerShape()
}

function changePointLayerShape() {
  pointLayer.shape(['pointType', 'id', 'status'], function (pointType, id, status) {
    return pointType;
  });
}


const domData = ref([])

const getRealTimeDataSource = (filedName, txt) => {
  const {pointData: {features}} = props
  if (!Array.isArray(features) || features.length <= 0) return []
  const baseData = features.filter(item => item?.properties?.pointId != null && item?.properties?.pointId !== '' && props.realTimeData.some(dataItem => dataItem.pointId === item?.properties?.pointId))
  return baseData.map(pointItem => {
    const {properties: {pointId}, geometry: {coordinates: [lng, lat]}} = pointItem;
    const dataItem = props.realTimeData.find(currentItem => currentItem.pointId === pointId)
    return {
      lng,
      lat,
      pointId,
      ...dataItem,
      domId: `${mapId}-${pointId}`
    }
  })
}

const initBackLayer = () => {
  domData.value.forEach(({lng, lat, domId}) => {
    const el = document.querySelector(`#${domId}`);
    const marker = new Marker({
      element: el,
      offsets: [props.offsetX, props.offsetY],
    }).setLnglat({lng, lat});
    scene.addMarker(marker);
  })
}

const changeRealTimeDataLayer = () => {
  const bufferValue = getRealTimeDataSource()
  if (!Array.isArray(domData.value) || domData.value.length <= 0) {
    domData.value = bufferValue
    nextTick(() => {
      initBackLayer()
    })
  }
  domData.value = bufferValue
}

watch(() => props.realTimeData, () => {
  if (scene == null) return
  changeRealTimeDataLayer()
}, {
  deep: true,
  immediate: true
})

let clickPointData = []

let clickPointLayer = null

const changePointLayerData = () => {
  const clickLayerDataSource = clickPointLayer.getSource()
  clickLayerDataSource.setData(clickPointData)
}

function addClickLayer() {
  clickPointLayer = new PointLayer()
      .source(clickPointData, {
        parser: {
          type: 'json',
          x: 'lng',
          y: 'lat',
        },
      })
      .size(15)
      .shape('lng_lat', 'text')
      .style({
        textAnchor: 'center', // 文本相对锚点的位置 center|left|right|top|bottom|top-left
        spacing: 2, // 字符间距
        padding: [1, 1], // 文本包围盒 padding [水平，垂直]，影响碰撞检测结果，避免相邻文本靠的太近
        stroke: '#000', // 描边颜色
        strokeWidth: 0.3, // 描边宽度
        strokeOpacity: 1.0,
        fontFamily: 'Times New Roman',
        textAllowOverlap: true,
      })
  scene.addLayer(clickPointLayer);

  scene.on('click', (e) => {
    const {lnglat: {lng, lat}} = e
    clickPointData.push({
      lng: lng,
      lat: lat,
      lng_lat: `经纬度：[${lng} , ${lat}]`
    })
    console.log(JSON.stringify([lng, lat]))
    changePointLayerData()
  });
}

function initMap() {
  createScene()
  scene.on('loaded', () => {
    setMapStatus()
    addMapImageSource()
    addLineLayerData()
    addPointLayer()
    props.addPointMode && addClickLayer()
    initPointLayerSource()
  });
}

onMounted(() => {
  nextTick(() => {
    initMap()
  })
})
</script>

<style scoped lang="scss">
.flow-chart-root {
  width: 100%;
  height: 100%;
  background-color: lightblue;

  :deep(.amap-container) {
    background-image: none;
    background-color: transparent;
  }

  :deep(.data-txt-container) {
    background-color: #4cade8;
    position: relative;
    display: flex;
    flex-direction: column;
    box-sizing: border-box;
    padding: 5px 10px;
    border-radius: 5px;

    .txt-item {
      display: flex;
      gap: 10px;

      .label, .value {
        display: flex;
        align-items: center;
        font-size: 12px;
      }

    }
  }
}
</style>
